﻿using QDasConverter.Core;
using QDasConverter.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;

namespace QDasConverter.Core
{
    public class SqlConvertProcessor
    {
        object locker = new object();
        Thread mainThread;
        bool isPaused = false;
        bool isStopping = false;
        IniAccess ia = new IniAccess();

        /// <summary>
        /// 上一次的处理时间。
        /// </summary>
        DateTime lastProcessTime = new DateTime(2020, 1, 1);


        /// <summary>
        /// 是否是背景线程运行，默认值为true.
        /// </summary>
        public bool IsBackground = true;


        /// <summary>
        /// SQL处理器对应的转换器
        /// </summary>
        public ConvertBase Converter;


        /// <summary>
        /// 线程是否已经停止。
        /// </summary>
        public bool Terminated { get => mainThread == null || mainThread.ThreadState == ThreadState.Stopped; }


        /// <summary>
        /// 当文件转换完成时发生此事件。
        /// </summary>
        public event TransFileCompleteEventHandler OneStepProcessCompleted;


        /// <summary>
        /// 线程退出发生。
        /// </summary>
        public event EventHandler ProcessExited;

        /// <summary>
        /// 以一个转换器模块初始化SQL处理器
        /// </summary>
        /// <param name="converter"></param>
        public SqlConvertProcessor(ConvertBase converter)
        {
            if (converter == null)
                throw new ArgumentNullException("参数 converter 不能为空。");
            Converter = converter;
            Initialize();
        }


        /// <summary>
        /// 获得转换器的相关信息用于初始化。
        /// </summary>
        public virtual void Initialize()
        {
            Converter.Initialize();
        }



        /// <summary>
        /// 启动线程。
        /// </summary>
        public virtual void Start()
        {
            if (mainThread == null)
            {
                mainThread = mainThread ?? new Thread(MainThreadProcess);
                mainThread.IsBackground = IsBackground;
                mainThread.Start();
            }
            else if (mainThread.ThreadState == ThreadState.Running)
            {
                Common.AddLog($"当前线程({mainThread.ManagedThreadId}:{mainThread.Name})运行中，启动失败。", LogType.Error);
                return;
            }
            else
            {
                var log = $"Start failed: Current ThreadState={mainThread.ThreadState}";
                Console.WriteLine(log);
                Common.AddLog(log, LogType.Error);
            }
        }

        /// <summary>
        /// 终止线程。
        /// </summary>
        /// <returns></returns>
        public void Stop()
        {
            if ((mainThread.ThreadState & ThreadState.Running) == ThreadState.Running
                || (mainThread.ThreadState & ThreadState.Background) == ThreadState.Background)
            {
                OnStopping();
                isStopping = true;

                // 等待30秒，如果仍然没有结束，则调用About强制结束线程。
                var now = DateTime.Now;
                while ((mainThread.ThreadState & ThreadState.Stopped) != ThreadState.Stopped)
                {
                    Thread.Sleep(10);
                    if ((DateTime.Now - now).TotalSeconds > 1)
                    {
                        mainThread.Abort();
                        Console.WriteLine("Forcely About.");
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// 线程执行的主程序。
        /// </summary>
        public void MainThreadProcess()
        {
            // 保证转换模块不为空，如果为空则直接抛出异常。
            if (Converter == null)
                throw new NullReferenceException("Converter为null，无法启动转换模块。");

            // 检测连接是否正常，如果不正常则弹出提示对话框并退出
            if (Converter.NeedConnectionCheck)
            {
                var connected = SqlConvertProcessor.TryConnection(Converter.SqlConnectionString, 3);
                if (!connected)
                {
                    Common.AddLog($"无法通过连接字符串连接数据库, 连接字符串：{Converter.SqlConnectionString}", LogType.Error);
                    MessageBox.Show($"无法通过连接字符串连接数据库\n连接字符串：{Converter.SqlConnectionString}", "字符串连接失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                Common.AddLog($"数据库连接成功，连接字符串 '{Converter.SqlConnectionString}' 连接正常。", LogType.INFO);
            }

            if(!string.IsNullOrEmpty(Converter.SqlConnectionString))
                Converter.sm = new WindGoes6.Database.SQLManager(Converter.SqlConnectionString);


            // 保证路径是绝对路径。
            Converter.TempDirectory = Path.GetFullPath(Converter.TempDirectory);
            Converter.OutputDirectory = Path.GetFullPath(Converter.OutputDirectory);
            Converter.LastResID = ia.ReadInt(Config.LastResID, 0);
            Converter.ConvertInterval = ia.ReadInt(Config.ConvertInterval, 60);
            Converter.BatchCount = ia.ReadInt(Config.BatchCount, 50);

            // 为测试方便，转换周期改为1秒
            Converter.ConvertInterval = 1;

            if (!Converter.OnStart())
            {
                Common.AddLog("Failed to start.", LogType.Fatal);
                return;
            }
            try
            {
                do
                {
                    // 每1ms检测一次根据Interval是否需要处理业务。
                    var now = DateTime.Now;
                    if ((now - lastProcessTime).TotalSeconds < Converter.ConvertInterval)
                    {
                        Thread.Sleep(1);
                        continue;
                    }
                    lastProcessTime = now;

                    // 判断循环是否结束
                    if (Converter.IsLoopCompleted())
                        break;

                    // 判断是否需要开始下次循环。
                    if (!Converter.NeedConvert())
                        continue;

                    // 准备开始执行，比如清空ResultFiles。
                    OneLoop_Prepare(); 
                    
                    // 循环处理。
                    Converter.OneLoop_Process();


                    // 更新LastResID，记录数据等操作。
                    OneLoop_Completed(); 

                    // 是否暂停。
                    while (IsPaused())
                        Thread.Sleep(1);

                } while (!isStopping);
            }
            catch (Exception ex)
            {
                Common.AddLog(ex.Message, LogType.Fatal);
            }

            OnExiting();
        }

        /// <summary>
        /// 转换线程在退出时执行的相关操作。
        /// </summary>
        private void OnExiting()
        {
            Converter.OnStopped();
            // 程序退出时保存 LastResID
            ia.WriteValue(Config.LastResID, Converter.LastResID.ToString());
            ProcessExited?.Invoke(this, EventArgs.Empty);
        }

        /// <summary>
        /// 处理完后会更新 LastResID
        /// </summary>
        private void OneLoop_Completed()
        {
            // 更新LastResID
            Converter.UpdateLastResId();

            Converter.OneLoop_Completed();

            // 处理完成的相关内容，并处理相应的日志信息
            lock (Converter.ConversionMessages) // 对处理的结果信息进行处理
            {
                // 用于回调函数传值，前端可以显示转换完成情况。
                var msgs = new List<TransLog>();

                // 统计情况
                string convertSummury = $"最后编号: {Converter.LastResID}, ";
                convertSummury += $"转换行数: {Converter.BatchCount}, ";
                convertSummury += $"转换间隔: {Converter.ConvertInterval}s, ";
                convertSummury += $"输出文件数量: {Converter.ResultFiles.Count}.";

                msgs.Add(new TransLog(LogType.INFO, convertSummury));
                // 获得转换器内部的一些消息
                foreach (var msg in Converter.ConversionMessages)
                    msgs.Add(msg);

                // 清空数据，并通过回调函数将日志信息传给前端。
                Converter.ConversionMessages.Clear();
                OneStepProcessCompleted?.Invoke(this, msgs);
            }
        }

        /// <summary>
        /// 会清空ResultFiles
        /// </summary>
        private void OneLoop_Prepare()
        {
            Converter.ResultFiles.Clear();
            Converter.OneLoop_Prepare();
        }

        /// <summary>
        /// 测试连接是否正常。
        /// </summary>
        /// <param name="constr">待测试连接字符串。</param>
        /// <param name="timeout">测试时间，默认为3秒。</param>
        /// <returns></returns>
        public static bool TryConnection(string constr, int timeout = 1)
        {
            bool success = false;
            WindGoes6.Data.MultiThreadSqlCon mt = new WindGoes6.Data.MultiThreadSqlCon();
            mt.ConnectionString = constr;
            mt.Timeout = timeout;
            mt.AfterTest += (connected, error) => success = connected;
            mt.StartTest();
            var now = DateTime.Now;
            while ((DateTime.Now - now).TotalSeconds < timeout)
                Thread.Sleep(1);
            Thread.Sleep(100);
            return success;
        }



        /*********************************************** 以下内容暂时保留 ***********************************************/

        /// <summary>
        /// 当前线程是否是暂停状态。
        /// </summary>
        /// <returns></returns>
        public bool IsPaused()
        {
            return isPaused;
        }

        public void Pause()
        {
            lock (locker)
            {
                isPaused = true;
            }
        }

        public void Continue()
        {
            lock (locker)
            {
                isPaused = true;
            }
        }


        /// <summary>
        /// 线程将要暂停时要做的事情。
        /// </summary>
        public virtual void OnPausing()
        {

        }

        /// <summary>
        /// 线程调用Stop()方法之前时要做的事情。
        /// </summary>
        public virtual void OnStopping()
        {
            Console.WriteLine("OnStopping");
        }




        /// <summary>
        /// 主函数，格式如下：201904 operation args 
        /// </summary>
        /// <param name="args"></param>
        public string Convert(string cid, string input, string output)
        {
            ConvertBase convert = GetConvertByName(cid);
            if (convert == null)
                return "failed";

            return convert.Convert(input, output).ToString();
        }

        /// <summary>
        /// 返回格式为：无锡联合汽车电子转换EXCEL转换器||V1.0.2||xls.xlsx
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public ConvertBase GetConvertByName(string name)
        {
            Assembly asm = Assembly.GetExecutingAssembly();
            bool p(Type t) => t.Name.Contains(name);
            Type type = asm.GetTypes().Count(p) > 0 ? asm.GetTypes().First(p) : null;
            return type == null ? null : (ConvertBase)Activator.CreateInstance(type);
        }

    }
}
